package com.qudian.pay.log.aop;

import java.net.InetAddress;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.qudian.pay.core.aop.BaseInterceptor;
import com.qudian.pay.core.diagnostic.Profiler;
import com.qudian.pay.core.runtime.MdcHolder;
import com.qudian.pay.core.runtime.ProductContext;
import com.qudian.pay.core.runtime.ProductContextHolder;
import com.qudian.pay.core.runtime.ProductEnvironment;
import com.qudian.pay.core.utils.AnnotatedUtils;
import com.qudian.pay.core.utils.IPUtils;
import com.qudian.pay.log.annotation.PerformLog;

/**
 * @Description: 入口层性能日志拦截器
 * @author gaoxiang
 * @date 2015年11月17日 下午10:32:33
 */
public class PerformanceInterceptor extends BaseInterceptor {
	
	private final static Logger logger = LoggerFactory.getLogger("PERFORM");
	
	/**
	 * @Fields threshold : 以毫秒表示的阈值
	 */
	private int threshold = 500;
	
	private String layerName = "undefined";
	
	@Override
	public Object bizInvoke(MethodInvocation invocation) throws Throwable {
		//作为入口需要初始化环境信息
		if (!Profiler.isSuperStart() && MdcHolder.unInit()) {
			ProductContext productContext = ProductContextHolder.getProductContext();
			productContext.setEnvironment(new ProductEnvironment(IPUtils.getIp4Single(), IPUtils.getIp4Single(), InetAddress.getLocalHost().getHostName()));
			MdcHolder.init(productContext);
		}
		StringBuilder builder = new StringBuilder(64);
		builder.append(invocation.getMethod().getDeclaringClass().getName()).append(".").append(invocation.getMethod().getName());
		String name = builder.toString();
		Profiler.start("Invoking "+layerName+" method: " + name);
		try {
			return invocation.proceed();
		} finally {
			Profiler.release();
			if (!Profiler.isSuperStart()) {
				long elapseTime = Profiler.getDuration();
				PerformLog performLog = AnnotatedUtils.getAnnotated(PerformLog.class, invocation);
				// 如果方法调用时间超过 阈值,或者加入了PerformLog注解 则打印service性能日志
				if ((performLog == null && elapseTime > threshold) || (performLog != null && elapseTime > performLog.threshold())) {
					StringBuilder builderTmp = new StringBuilder();
					builderTmp.append(" Start "+layerName+" method : " + invocation.getMethod().getDeclaringClass().getName())
							// 阈值时间
							.append(" threshold = ").append(threshold).append("ms,");
					// 实际执行时间为
					builderTmp.append(" used = ").append(elapseTime).append("ms.\r\n");
					builderTmp.append(Profiler.dump());
					logger.info(builderTmp.toString());
				}
				MdcHolder.clean();
				ProductContextHolder.clean();
			}
			Profiler.reset();
		}
	}
	
	public void setThreshold(int threshold) {
		this.threshold = threshold;
	}
	
	public void setLayerName(String layerName) {
		this.layerName = layerName;
	}
}
